package com.dkha.server.services.impl;

import com.alibaba.fastjson.JSONObject;
import com.dkha.common.enums.ApiUrlEnum;
import com.dkha.common.exception.DkException;
import com.dkha.common.fileupload.MinioUtil;
import com.dkha.common.http.HttpUtil;
import com.dkha.common.modules.vo.ReturnVO;
import com.dkha.common.modules.vo.cut.CutVo;
import com.dkha.common.modules.vo.face.ApiSearchFaceRectVO;
import com.dkha.common.modules.vo.position.PositionVO;
import com.dkha.common.modules.vo.upload.ImageUploadResult;
import com.dkha.common.util.Base64ImageUtils;
import com.dkha.common.util.IntUUID;
import com.dkha.common.util.JsonUtil;
import com.dkha.common.util.UtilValidate;
import com.dkha.server.services.IFileService;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @Author Spring
 * @Since 2019/12/11 15:41
 * @Description 文件上传相关
 */
@Component
@Slf4j
public class FileServiceImpl implements IFileService {

    @Value("${api.server.prefix}")
    private String apiRequestPrefix;
    @Autowired
    private HttpUtil httpUtil;
    @Autowired
    private MinioUtil minioUtil;
    @Value("${api.picture.type}")
    private String apiPictureType;

    @Override
    public ImageUploadResult uploadMultiFaceImages(MultipartFile[] multipartFiles) throws Exception {
        if (UtilValidate.isEmpty(multipartFiles)) {
            throw new DkException("请上传图片");
        }
        List<String> imageUrlList = new ArrayList<>();
        for (MultipartFile file : multipartFiles) {
            JSONObject map = minioUtil.uploadFile(file.getInputStream(), this.generateFileName(file.getOriginalFilename()), null);
            if (UtilValidate.isNotEmpty(map) && map.get("flag").equals("0")) {
                imageUrlList.add(map.get("url").toString());
            } else {
                throw new DkException("文件上传异常");
            }
        }
        return this.validateMultiFaceImages(imageUrlList);
    }

    @Override
    public ImageUploadResult uploadSingleFaceImage(MultipartFile[] multipartFiles) throws Exception {
        if (UtilValidate.isEmpty(multipartFiles)) {
            throw new DkException("请上传图片");
        }
        if (multipartFiles.length > 1) {
            throw new DkException("只能上传单张图片");
        }

        List<String> imageUrlList = new ArrayList<>();
        for (MultipartFile file : multipartFiles) {
            //获取文件后缀
            JSONObject map = minioUtil.uploadFile(file.getInputStream(), this.generateFileName(file.getOriginalFilename()) , null);
            if (UtilValidate.isNotEmpty(map) && map.get("flag").equals("0")) {
                imageUrlList.add(map.get("url").toString());
            } else {
                throw new DkException("文件上传异常");
            }
        }
        this.validateSingleFaceImage(imageUrlList);
        ImageUploadResult imageUploadResult = new ImageUploadResult();
        imageUploadResult.setSuccessFiles(imageUrlList.size());
        imageUploadResult.setSuccessFileUrlList(imageUrlList);
        return imageUploadResult;
    }

    @Override
    public String cutPicture(CutVo cutVo) throws Exception {
        PositionVO positionVO = new PositionVO();
        positionVO.setH(cutVo.getH());
        positionVO.setW(cutVo.getW());
        positionVO.setX(cutVo.getX());
        positionVO.setY(cutVo.getY());
        BufferedImage bufferedImage = ImageIO.read(new URL(cutVo.getUrl()));
//        positionVO = Base64ImageUtils.deelPostion(positionVO, bufferedImage.getWidth(), bufferedImage.getHeight());
        InputStream inputStream = Base64ImageUtils.encodeHeadImage(bufferedImage, positionVO);
        String fileName = this.generateFileName(cutVo.getUrl());
        JSONObject map = minioUtil.uploadFile(inputStream, fileName, null);
        if (UtilValidate.isNotEmpty(map) && map.get("flag").equals("0")) {
            return map.get("url").toString();
        }
        throw new DkException("文件上传异常");
    }

    /**
     * 单图上传,其中一张图只能有一张人脸 校验
     * @param images 图片路径集合
     */
    private ImageUploadResult validateMultiFaceImages(List<String> images) {
        //人脸检测url
        String faceSearchUrl = apiRequestPrefix + ApiUrlEnum.FACE_SEARCH.getUrl();
        //组织返回结果集
        ImageUploadResult imageUploadResult = new ImageUploadResult();
        for (String image : images) {
            //组装api请求数据
            ReturnVO returnVO = (ReturnVO) httpUtil.post(faceSearchUrl + "?url=" + image, null, ReturnVO.class);
            if (returnVO.getCode() != 200) {
                throw new DkException(returnVO.getMessage());
            }
            //反序列化
            List<ApiSearchFaceRectVO> apiSearchFaceRectVOList = JsonUtil.string2Obj(JsonUtil.obj2String(returnVO.getData()), new TypeReference<List<ApiSearchFaceRectVO>>() {});
            if (UtilValidate.isEmpty(apiSearchFaceRectVOList)) {
                throw new DkException("当前上传中未检测到人脸,请重新上传");
            }
            //检测成功集合
            List<String> successUrlList = new ArrayList<>();
            for (ApiSearchFaceRectVO apiSearchFaceRectVO : apiSearchFaceRectVOList) {
                successUrlList.add(apiSearchFaceRectVO.getUrl());
            }
            imageUploadResult.setSuccessFileUrlList(successUrlList);
            imageUploadResult.setSuccessFiles(successUrlList.size());
            imageUploadResult.setFailFiles(images.size() - successUrlList.size());
            imageUploadResult.setTotalFiles(images.size());
        }
        return imageUploadResult;
    }

    /**
     * 多图/单图上传,其中一张图可以多人脸/单人脸 校验
     * @param images
     */
    private void validateSingleFaceImage(List<String> images) {
        //人脸检测url
        String faceSearchUrl = apiRequestPrefix + ApiUrlEnum.FACE_SEARCH.getUrl();
        for (String image : images) {
            //组装api请求数据
            ReturnVO returnVO = (ReturnVO) httpUtil.post(faceSearchUrl + "?url=" + image, null, ReturnVO.class);
            if (returnVO.getCode() != 200) {
                throw new DkException(returnVO.getMessage());
            }
            //反序列化
            List<ApiSearchFaceRectVO> apiSearchFaceRectVOList = JsonUtil.string2Obj(JsonUtil.obj2String(returnVO.getData()), new TypeReference<List<ApiSearchFaceRectVO>>() {});
            if (UtilValidate.isEmpty(apiSearchFaceRectVOList)) {
                throw new DkException("当前上传中未检测到人脸,请重新上传");
            }
            if (apiSearchFaceRectVOList.size() > 1) {
                throw new DkException("当前上传图片检测到多张人脸,请重新上传");
            }
        }
    }

    /**
     * 生成唯一文件名
     * @param originFileName
     * @return
     */
    private String generateFileName(String originFileName) {
        // todo 迁移到资源文件中
        //当前时间
        long timeMillis = System.currentTimeMillis();
        int shortUUID = IntUUID.getShortUUID();
        if (!originFileName.contains(".")) {
            throw new DkException("文件名格式错误");
        }
        String[] originalFileNameCompose = originFileName.split("\\.");
        //获取原文件后缀
        String originalFileNameSuffix = originalFileNameCompose[originalFileNameCompose.length - 1];
        Pattern p = Pattern.compile(apiPictureType);
        boolean flag = p.matcher(originalFileNameSuffix).find();
        if (!flag) {
            throw new DkException("请上传.jpg .png .jpeg类型的图片");
        }
        return timeMillis + "-" + shortUUID + "." + originalFileNameSuffix;
    }
}
